/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rpc.remote.http.service;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import io.iec.edp.caf.common.JSONSerializer;
import io.iec.edp.caf.commons.core.SerializerFactory;
import io.iec.edp.caf.commons.core.enums.SerializeType;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;

import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.core.context.ICAFContextService;
import io.iec.edp.caf.core.session.ICafSessionService;
import io.iec.edp.caf.logging.CommonConstant;
import io.iec.edp.caf.rest.client.RESTProxyClientFactory;
import io.iec.edp.caf.rpc.api.entity.RpcServiceMethodDefinition;
import io.iec.edp.caf.rpc.api.event.RpcClientEventBroker;
import io.iec.edp.caf.rpc.api.serialize.RpcSerializeUtil;
import io.iec.edp.caf.rpc.api.support.ConstanceVarible;
import io.iec.edp.caf.rpc.api.support.RpcTimeoutHolder;
import io.iec.edp.caf.rpc.api.support.Type;

import io.iec.edp.caf.rpc.api.utils.Validator;
import io.iec.edp.caf.rpc.remote.http.WebApiException;
import io.iec.edp.caf.rpc.remote.http.api.RpcServiceApi;
import io.iec.edp.caf.rpc.remote.http.entity.RpcStreamParam;
import io.iec.edp.caf.rpc.server.invoker.RpcRemoteInvoker;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.apache.cxf.ext.logging.LoggingFeature;
import org.apache.cxf.feature.Feature;
import org.apache.cxf.jaxrs.client.Client;
import org.apache.cxf.jaxrs.client.ClientConfiguration;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.AttachmentBuilder;
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;

import javax.servlet.http.Cookie;
import javax.ws.rs.InternalServerErrorException;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static java.util.stream.Collectors.toList;

/**
 * @author Leon Huo
 * @Date: 2021/5/31
 */
@Slf4j
public class RpcRemoteInvokerImpl  implements RpcRemoteInvoker {

    public RpcRemoteInvokerImpl(RpcClientEventBroker clientEventBroker) {
        this.clientEventBroker = clientEventBroker;
        //this.rpcAddressDiscover = rpcAddressDiscover;
    }
    private ICAFContextService contextService = SpringBeanUtils.getBean(ICAFContextService.class);

    private RpcClientEventBroker clientEventBroker;

   // private RpcAddressDiscover rpcAddressDiscover;

    private static final String BASE_PATH = "/api/runtime/communication/v1.0/rpc/";

    private static final String BASE_STREAMUP_PATH = "/api/runtime/communication/v1.0/rpc/streamup/";
//    private static final String BASE_STREAMDOWN_PATH = "/api/runtime/communication/v1.0/rpc/streamdown/";

    private int DEFAULT_TIMEOUT = 300000;

    private Map<String,RpcServiceApi> restProxyCache = new HashMap<>();

//    @Override
//    public Object remoteInvokeByAddress(Class clazz, String serviceId, String address, HashMap<String, Object> parameters, Cookie[] cks, RpcServiceMethodDefinition rpcServiceMethodDefinition,HashMap<String, String> eventContext) throws IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchMethodException, InvocationTargetException {
//        String remoteUrl = address;
//
//        URL url = new URL(String.format("%s%s", remoteUrl, BASE_PATH));
//        //创建公共的RPCController的代理
//        var service = RESTProxyClientFactory.build(RpcServiceApi.class, url);
//
//        Client webClient = WebClient.client(service);
//
////        //校验下cookie是否存在，记录下日志，用来排查偶发401问题
////        Validator.CheckCksSession(cks,serviceId);
//
//        //还原cookie
//        if (cks != null && cks.length > 0) {
//            for (var c : cks) {
//                webClient.cookie(new javax.ws.rs.core.Cookie(c.getName(), c.getValue()));
//            }
//        }
//        //todo 临时设置固定超时时间，后面完善时整改
//        ClientConfiguration config = WebClient.getConfig(webClient);
//        config.getHttpConduit().getClient().setReceiveTimeout(DEFAULT_TIMEOUT);
////        config.getHttpConduit().getClient().setContentType("application/json");
//
//        //还原gspContext
//        HashMap<String, String> gspContext = new HashMap<String, String>();
//        var sessionId = "";
//
//        //这里先默认塞N版的contextid吧
//        if (cks != null && cks.length > 0) {
//            List<Cookie> ck = Arrays.stream(cks).filter(c -> c.getName().equalsIgnoreCase(ConstanceVarible.NET_SESSON_ID)).collect(toList());
//            sessionId = (ck != null && ck.size() > 0) ? ck.get(0).getValue() : sessionId;
//        }
//        gspContext.put(ConstanceVarible.GSP_CONTEXT_ID, sessionId);
//        gspContext.put(ConstanceVarible.GSP_RPC, "true");
//
//        eventContext.put(ConstanceVarible.CURRENT_SERVICE_INTERFACE, serviceId);
//
//        //序列化处理入参
//        LinkedHashMap<String, String> params = rpcServiceMethodDefinition == null ?
//                RpcSerializeUtil.serializeParameter(parameters) :
//                RpcSerializeUtil.serializeParameter(parameters, rpcServiceMethodDefinition.getParameters());
//
//        var localDict = new HashMap<String, Object>();
//        try {
//            this.clientEventBroker.firePreRpcInvokeEvent(eventContext, parameters, localDict);
//            gspContext.put(ConstanceVarible.GSP_RPC_CLIENT_ENVENT, SerializerFactory.getSerializer(SerializeType.Json).serializeToString(eventContext));
////            WebClient.client(service).header("gsp-context", SerializerFactory.getSerializer(SerializeType.Json).serializeToString(gspContext));
//            String traceId = (String) localDict.get(CommonConstant.LOG_TRACE_ID);
//            WebClient.client(service)
//                    .header(ConstanceVarible.GSP_CONTEXT, JSONSerializer.serialize(gspContext))
//                    .header(CommonConstant.TRACE_ID_HEADER, traceId);
//
//
//            //远程访问
//            Object result = service.invoke(serviceId, "1.0", params);
//            var response = webClient.getResponse();
//            //set some context for early net core
//            if (!"j".equals(response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER)))
//                result = JSONSerializer.deserialize((String) result, String.class);
//
//            //获取返回值
//            var serverContextString = response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER_ENVENT);
//            var serverContextDict = JSONSerializer.deserialize(serverContextString, LinkedHashMap.class);
//            this.clientEventBroker.firePostRpcInvokeEvent(serverContextDict, result, localDict);
//
//            //TODO:序列化
//            return RpcSerializeUtil.deSerializeReturnValue(new Type(clazz), result, rpcServiceMethodDefinition);
////            returnValueSerializer.deSerializeReturnValue(clazz, result, rpcServiceMethodDefinition);
//
//        } catch (Exception ex) {
//            this.clientEventBroker.fireExceptionRpcInvokeEvent(eventContext, parameters, localDict, ex);
//            if (ex instanceof InternalServerErrorException) {
//                var stream = ((InternalServerErrorException) ex).getResponse().getEntity();
//
//                BufferedReader tBufferedReader = new BufferedReader(new InputStreamReader((InputStream) stream, StandardCharsets.UTF_8));
//
//                StringBuilder tStringBuffer = new StringBuilder();
//
//                String sTempOneLine;
//
//                while ((sTempOneLine = tBufferedReader.readLine()) != null) {
//                    tStringBuffer.append(sTempOneLine);
//                }
//                String errorInfo = tStringBuffer.toString();
//                WebApiException webApiException = SerializerFactory.getSerializer(SerializeType.Json).deserialize(errorInfo, WebApiException.class);
//                throw new CAFRuntimeException("caf", "Communication", webApiException.getMessage(), ex, ExceptionLevel.Error, true);
//            } else
//                throw ex;
//        }
//    }


    /**
     * invoke remote rpc service
     * @param type                       return value type
     * @param serviceId                  serviceid
     * @param parameters                 service parameters
     * @param cks                        cookies
     * @param rpcServiceMethodDefinition service definition
     * @param <T>                        return type
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    @SneakyThrows
    @Override
    public <T> T invokeRemoteService(Type<T> type, String serviceId, String serviceUnitName,String remoteUrl, HashMap<String, Object> parameters, Cookie[] cks, RpcServiceMethodDefinition rpcServiceMethodDefinition, Integer tenantId,HashMap<String, String> eventContext){
//            RpcServiceApi service = (RpcServiceApi)restProxyCache.get(remoteUrl);
//        if(service==null){
//            URL url = new URL(String.format("%s%s", remoteUrl, BASE_PATH));
//            //create rpc http proxy
//            service = RESTProxyClientFactory.build(RpcServiceApi.class, url);
//            restProxyCache.put(remoteUrl,service);
//        }
        URL url = new URL(String.format("%s%s", remoteUrl, BASE_PATH));
        RpcServiceApi service = RESTProxyClientFactory.build(RpcServiceApi.class, url);
        Client webClient = WebClient.client(service);
        //webClient.reset();

        //set http cookie
        setClientConfig(webClient,cks);

        //gsp context
        HashMap<String, String> gspContext = new HashMap<>();
        setGSPContext(gspContext,cks,serviceUnitName,tenantId,eventContext);

        //event context
        setEventContext(eventContext,rpcServiceMethodDefinition);

        //todo 这个判断不合适 不应依赖能否找到definition 后期调整
        LinkedHashMap<String, String> params = RpcSerializeUtil.serializeParameter(parameters, rpcServiceMethodDefinition);

        HashMap<String, Object> localDict = new HashMap<>();
        localDict.put(CommonConstant.LOG_MSU_ID, serviceUnitName);
        //before invoke event
        this.clientEventBroker.firePreRpcInvokeEvent(eventContext, parameters, localDict);

        try {
//            WebClient.client(service).header("gsp-context", SerializerFactory.getSerializer(SerializeType.Json).serializeToString(gspContext));
            String traceId = (String) localDict.get(CommonConstant.LOG_TRACE_ID);
            WebClient.client(service)
                    .header(ConstanceVarible.GSP_CONTEXT, JSONSerializer.serialize(gspContext))
                    .header(CommonConstant.TRACE_ID_HEADER, traceId);

            var start = System.currentTimeMillis();
            //remote invoke
            Object result = service.invoke(serviceId, "1.0", params);
            var end = System.currentTimeMillis();
            log.info("rpc remote invoke time：{} ms",end-start);

            var response = webClient.getResponse();
            //here is compatible the early net core
            if (!"j".equals(response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER)))
                result = JSONSerializer.deserialize((String) result, String.class);

            var serverContextString = response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER_ENVENT);
            var serverContextDict = JSONSerializer.deserialize(serverContextString, LinkedHashMap.class);

            this.clientEventBroker.firePostRpcInvokeEvent(serverContextDict, result, localDict);

            start = System.currentTimeMillis();
            T finalResult = RpcSerializeUtil.deSerializeReturnValue(type, result, rpcServiceMethodDefinition);
            end = System.currentTimeMillis();
            log.info("rpc remote invoke serialize time：{} ms",end-start);

            return finalResult;
        } catch (Exception ex) {
            this.clientEventBroker.fireExceptionRpcInvokeEvent(eventContext, parameters, localDict, ex);
            var e = handleException(ex,cks,serviceId,serviceUnitName);
            throw e;
        }finally {
            RpcTimeoutHolder.clearTimeout();
        }
    }

    @SneakyThrows
    @Override
    public InputStream invokeRemoteServiceStream(String serviceId,String version, String serviceUnitName, String remoteUrl, HashMap<String, Object> parameters, Cookie[] cks, RpcServiceMethodDefinition rpcServiceMethodDefinition, Integer tenantId, HashMap<String, String> eventContext) throws IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchMethodException, InvocationTargetException {

//        RpcServiceApi service = (RpcServiceApi)restProxyCache.get(remoteUrl);
//        if(service==null){
//            URL url = new URL(String.format("%s%s", remoteUrl, BASE_PATH));
//            //create rpc http proxy
//            service = RESTProxyClientFactory.build(RpcServiceApi.class, url);
//            restProxyCache.put(remoteUrl,service);
//        }
        URL url = new URL(String.format("%s%s", remoteUrl, BASE_PATH));
        RpcServiceApi service = RESTProxyClientFactory.build(RpcServiceApi.class, url);
        Client webClient = WebClient.client(service);
        //webClient.reset();

        //set http cookie
        setClientConfig(webClient,cks);

        //gsp context
        HashMap<String, String> gspContext = new HashMap<>();
        setGSPContext(gspContext,cks,serviceUnitName,tenantId,eventContext);

        //event context
        setEventContext(eventContext,rpcServiceMethodDefinition);

        //todo 这个判断不合适 不应依赖能否找到definition 后期调整
        LinkedHashMap<String, String> params = RpcSerializeUtil.serializeParameter(parameters, rpcServiceMethodDefinition);

        HashMap<String, Object> localDict = new HashMap<>();
        localDict.put(CommonConstant.LOG_MSU_ID, serviceUnitName);
        //before invoke event
        this.clientEventBroker.firePreRpcInvokeEvent(eventContext, parameters, localDict);

        try {
//            WebClient.client(service).header("gsp-context", SerializerFactory.getSerializer(SerializeType.Json).serializeToString(gspContext));
            String traceId = (String) localDict.get(CommonConstant.LOG_TRACE_ID);
            WebClient.client(service)
                    .header(ConstanceVarible.GSP_CONTEXT, JSONSerializer.serialize(gspContext))
                    .header(CommonConstant.TRACE_ID_HEADER, traceId);

            var start = System.currentTimeMillis();
            //remote invoke
            service.invokeStream(serviceId, version, params);
            var end = System.currentTimeMillis();
            log.info("rpc remote invoke time：{} ms",end-start);

            var response = webClient.getResponse();
//            InputStream result = new ByteArrayInputStream(new byte[0]);
//            result = (InputStream)response.getEntity();
            InputStream result = response.readEntity(InputStream.class);

//            var serverContextString = response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER_ENVENT);
//            var serverContextDict = JSONSerializer.deserialize(serverContextString, LinkedHashMap.class);
//            this.clientEventBroker.firePostRpcInvokeEvent(serverContextDict, "hera is invokeRemoteServiceStream return inputstream value,can not log here", localDict);

            return result;
        } catch (Exception ex) {
            this.clientEventBroker.fireExceptionRpcInvokeEvent(eventContext, parameters, localDict, ex);
            var e = handleException(ex,cks,serviceId,serviceUnitName);
            throw e;
        }finally {
            RpcTimeoutHolder.clearTimeout();
        }
    }

    @SneakyThrows
    @Override
    public <T> T invokeRemoteServiceStream(InputStream inputStream, Type<T> type, String serviceId,String version, String serviceUnitName, String remoteUrl, HashMap<String, Object> parameters, Cookie[] cks, RpcServiceMethodDefinition rpcServiceMethodDefinition, Integer tenantId, HashMap<String, String> eventContext) throws IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchMethodException, InvocationTargetException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

//        List<Object> providersList = new ArrayList<>();
//        providersList.add(new JacksonJsonProvider(mapper));

//        List<Feature> featureList = new ArrayList<Feature>() {{
//            add(new LoggingFeature());
//        }};
//        WebClient webClient = WebClient.create(String.format("%s%s", remoteUrl, BASE_STREAMUP_PATH),providersList,featureList,null);

        URL url = new URL(String.format("%s%s", remoteUrl, BASE_PATH));
        //创建公共的RPCController的代理
        RpcServiceApi service = RESTProxyClientFactory.build(RpcServiceApi.class, url);
        Client webClient = WebClient.client(service);

        //set http cookie
        setClientConfig(webClient,cks);
//        webClient.type("multipart/form-data");


        //gsp context
        HashMap<String, String> gspContext = new HashMap<>();
        setGSPContext(gspContext,cks,serviceUnitName,tenantId,eventContext);

        //event context
        setEventContext(eventContext,rpcServiceMethodDefinition);

        //todo 这个判断不合适 不应依赖能否找到definition 后期调整
        LinkedHashMap<String, String> params = RpcSerializeUtil.serializeParameter(parameters, rpcServiceMethodDefinition);

        HashMap<String, Object> localDict = new HashMap<>();
        localDict.put(CommonConstant.LOG_MSU_ID, serviceUnitName);
        //before invoke event
        this.clientEventBroker.firePreRpcInvokeEvent(eventContext, parameters, localDict);

        try {
            String traceId = (String) localDict.get(CommonConstant.LOG_TRACE_ID);
            webClient.header(ConstanceVarible.GSP_CONTEXT, JSONSerializer.serialize(gspContext))
                    .header(CommonConstant.TRACE_ID_HEADER, traceId);

//            WebClient.client(service).header("gsp-context", SerializerFactory.getSerializer(SerializeType.Json).serializeToString(gspContext));
//            webClient.header(ConstanceVarible.GSP_CONTEXT, JSONSerializer.serialize(gspContext));
//            webClient.header(CommonConstant.TRACE_ID_HEADER, traceId);

//            Attachment att = new Attachment("stream", inputStream, null);
//            Attachment attId = new Attachment("serviceid", "application/json", serviceId);
//            Attachment attVersion = new Attachment("version", "application/json", version);
//            Attachment attParam = new Attachment("params", "application/json", params);
//            List<Attachment> attmlist = new ArrayList<>();
//            attmlist.add(attId);
//            attmlist.add(attVersion);
//            attmlist.add(attParam);
//            attmlist.add(att);
//
//            MultipartBody body = new MultipartBody(attmlist);
            var start = System.currentTimeMillis();
            //remote invoke
            Object result = service.invokeStream(serviceId, "1.0", params, inputStream);
//            var result = webClient.post(body).readEntity(type.getRawType());
            var response = webClient.getResponse();
            var end = System.currentTimeMillis();
            log.info("rpc remote invoke time：{} ms",end-start);

            //here is compatible the early net core
//            if (!"j".equals(response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER)))
//                result = JSONSerializer.deserialize((String) result, String.class);

            var serverContextString = response.getHeaderString(ConstanceVarible.GSP_RPC_SERVER_ENVENT);
            var serverContextDict = JSONSerializer.deserialize(serverContextString, LinkedHashMap.class);

            this.clientEventBroker.firePostRpcInvokeEvent(serverContextDict, result, localDict);

            start = System.currentTimeMillis();
//            T finalResult = RpcSerializeUtil.deSerializeReturnValue(type, result, rpcServiceMethodDefinition);
            end = System.currentTimeMillis();
            log.info("rpc remote invoke serialize time：{} ms",end-start);

            //TODO 返回值为sequenceInputStream 暂时返回null
            return null;
        } catch (Exception ex) {
            this.clientEventBroker.fireExceptionRpcInvokeEvent(eventContext, parameters, localDict, ex);
            var e = handleException(ex,cks,serviceId,serviceUnitName);
            throw e;
        }finally {
            RpcTimeoutHolder.clearTimeout();
        }
    }

    @SneakyThrows
    private Exception handleException(Exception ex, Cookie[] cks, String serviceId, String serviceUnitName){
        if (ex instanceof InternalServerErrorException) {
            var stream = ((InternalServerErrorException) ex).getResponse().getEntity();
            BufferedReader tBufferedReader = new BufferedReader(new InputStreamReader((InputStream) stream, StandardCharsets.UTF_8));
            StringBuilder tStringBuffer = new StringBuilder();
            String sTempOneLine;

            while ((sTempOneLine = tBufferedReader.readLine()) != null) {
                tStringBuffer.append(sTempOneLine);
            }
            String errorInfo = tStringBuffer.toString();
            WebApiException webApiException = JSONSerializer.deserialize(errorInfo, WebApiException.class);

            //handle some exception
            handleHttp401Exception(cks,serviceId,serviceUnitName,ex);
            handleHttp500Exception(serviceId,serviceUnitName,ex);

            log.error("rpc remote invoke exception:"+ ex.getMessage(),ex);
            var excode = (webApiException.getCode()!=null && webApiException.getCode().length()>0)?webApiException.getCode():"Communication";
            return new CAFRuntimeException("caf", excode, webApiException.getMessage(), ex, ExceptionLevel.Error, true);
        } else {

            //handle some exception
            handleHttp401Exception(cks,serviceId,serviceUnitName,ex);
            handleHttp500Exception(serviceId,serviceUnitName,ex);

            log.error("rpc remote invoke exception:"+ ex.getMessage(),ex);
            return ex;
        }
    }

    private void setClientConfig(Client webClient,Cookie[] cks){
        //set cookie
        if (cks != null) {
            for (Cookie c : cks) {
                webClient.cookie(new javax.ws.rs.core.Cookie(c.getName(), c.getValue()));
            }
        }

        //get http client config
        ClientConfiguration config = WebClient.getConfig(webClient);

        //set rpc timeout in current thread，default 300000ms。
        if(RpcTimeoutHolder.getTimeout()!=null && RpcTimeoutHolder.getTimeout()>0){
            DEFAULT_TIMEOUT = RpcTimeoutHolder.getTimeout();
        }
        config.getHttpConduit().getClient().setReceiveTimeout(DEFAULT_TIMEOUT);
    }

    private void setGSPContext(Map<String,String> gspContext,Cookie[] cks,String serviceUnitName,Integer tenantId,Map<String,String> eventContext){
        String sessionId = "";
        //set some context for early net core
        if (cks != null && cks.length > 0) {
            List<Cookie> ck = Arrays.stream(cks).filter(c -> c.getName().equalsIgnoreCase(ConstanceVarible.NET_SESSON_ID)).collect(toList());
            sessionId = (ck != null && ck.size() > 0) ? ck.get(0).getValue() : sessionId;
        }

        gspContext.put(ConstanceVarible.GSP_CONTEXT_ID, sessionId);
        gspContext.put(ConstanceVarible.GSP_RPC, "true");
        gspContext.put(ConstanceVarible.GSP_MSU, serviceUnitName);
        if (tenantId != null) {
            gspContext.put(ConstanceVarible.GSP_RPC_TENANT, tenantId.toString());
        }
        gspContext.put(ConstanceVarible.GSP_RPC_CLIENT_ENVENT, SerializerFactory.getSerializer(SerializeType.Json).serializeToString(eventContext));

    }


    private void setEventContext(Map<String,String> eventContext,RpcServiceMethodDefinition rpcServiceMethodDefinition){
        eventContext.put(ConstanceVarible.CURRENT_SERVICE_INTERFACE, rpcServiceMethodDefinition == null ? null : rpcServiceMethodDefinition.getParentDefinition().getClassName());
    }

    private void handleHttp401Exception(Cookie[] cks, String serviceId, String su, Exception ex) {
        if (ex.getMessage().contains("HTTP 401 Unauthorized")) {
            log.error("RPC 401 exception: " + ex.getMessage());
            var sessionsrv = SpringBeanUtils.getBean(ICafSessionService.class);
            for (int i = 0; i < cks.length; i++) {
                log.error("Current serviceId: " + serviceId + ", target su：" + su + ", all cookies info: " + cks[i].getName() + ":" + cks[i].getValue());
                if (cks[i].getName().equals("caf_web_session")) {
                    var ss = cks[i].getValue();
                    if (ss != null) {
                        //base64解码cookie
                        String sessionId = new String(Base64.getDecoder().decode(ss), StandardCharsets.UTF_8);
                        log.error("Current sessionId {}, cookie {}", sessionId, ss);
                        //从redis里取下当前的session看是否过期
                        var session = sessionsrv.findById(sessionId);
                        log.error("Current session isExpired {}, value {}", sessionsrv.isExpired(sessionId), JSONSerializer.serialize(session));
                    } else {
                        log.error("Cookies has not caf_web_session");
                    }
                }
            }
        }
    }

    private void handleHttp500Exception(String serviceId, String su, Exception ex) {
        if (ex.getMessage().contains("HTTP 500 Internal Server Error")) {
            log.error("RPC 500 exception: {}, Current serviceId: {}, target su: {}, current exception is RPC Remote Invoke client exception, please check the logging in target su: {}", ex.getMessage(), serviceId, su, su);
        }
    }

}

